package middleware

import (
	"net/http/httputil"
	"net/url"
	"regexp"
	"strings"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/response"
	"192.168.1.75/go-pkg/svsdis"
	"github.com/gin-gonic/gin"
)

// Proxy 反向代理
func Proxy() gin.HandlerFunc {
	ServiceDefine := map[string]string{
		"system-admin": "系统后台",
		"device-admin": "设备后台",
		"sale-admin":   "售卖后台",
		"open-api":     "开放接口",
		"mini-app":     "小程序",
	}

	// 非system-admin的服务，反向代理到响应服务
	return func(c *gin.Context) {
		urlPath := c.Request.URL.Path

		// 去掉重复的 '/'
		pattern := regexp.MustCompile(`\/+`)
		urlPath = string(pattern.ReplaceAll([]byte(urlPath), []byte("/")))

		// path 转为数组
		urlPathArr := strings.Split(urlPath, "/")
		urlPathArr = urlPathArr[1:] // 去除首个空path字段
		if len(urlPathArr) < 2 {
			response.JSON(c, nil, errorx.New("无效的url", -1))
			return
		}

		// 获取微服务名称
		serviceName := urlPathArr[0]

		// 不存在的服务名字，默认为售卖后台，为了向后兼容app
		// web端可以直接在线升级
		if ServiceDefine[serviceName] == "" {
			serviceName = "sale-admin"
			urlPathArr = append([]string{serviceName}, urlPathArr...)
		}

		// 反向代理处理
		{
			switch serviceName {
			// 系统后台
			case "system-admin":
				c.Next()
			// 反向代理到其他微服务
			default:
				// 服务发现
				serviceConf := svsdis.FindService(serviceName)

				serviceConfArr := strings.Split(serviceConf, ":")
				if serviceConf == "" || len(serviceConfArr) < 2 {
					response.JSON(c, nil, errorx.New("访问的服务不存在", -1))
					return
				}

				// 计算反向代理的地址
				hostPort := serviceConfArr[0] + ":" + serviceConfArr[1]
				remote, err := url.Parse("http://" + hostPort)
				if err != nil {
					response.JSON(c, nil, errorx.New("无效的url", -1))
					return
				}

				// 反向代理
				c.Request.URL.Path = "/" + strings.Join(urlPathArr[1:], "/")
				proxy := httputil.NewSingleHostReverseProxy(remote)

				// 为websocket手动添加Upgrade和Connection头
				if strings.Contains(urlPath, "websocket") {
					c.Request.Header.Add("Upgrade", "websocket")
					c.Request.Header.Add("Connection", "upgrade")
					c.Request.Header.Add("Sec-Websocket-Version", "13")
				}
				proxy.ServeHTTP(c.Writer, c.Request)
				return
			}
		}
	}
}
